#!/usr/bin/env python

"""Ninja build generator"""

import argparse
import os
import pipes
import sys

import platform
import toolchain
import syntax


class Generator(object):
    def __init__(
        self, project, includepaths=[], dependlibs=[], libpaths=[], variables=None
    ):
        parser = argparse.ArgumentParser(description="Ninja build generator")
        parser.add_argument(
            "-t",
            "--target",
            help="Target platform",
            choices=platform.supported_platforms(),
        )
        parser.add_argument(
            "--host", help="Host platform", choices=platform.supported_platforms()
        )
        parser.add_argument(
            "--toolchain",
            help="Toolchain to use",
            choices=toolchain.supported_toolchains(),
        )
        parser.add_argument(
            "-c",
            "--config",
            action="append",
            help="Build configuration",
            choices=["debug", "release", "profile", "deploy"],
            default=[],
        )
        parser.add_argument(
            "-a",
            "--arch",
            action="append",
            help="Add architecture",
            choices=toolchain.supported_architectures(),
            default=[],
        )
        parser.add_argument(
            "-i", "--includepath", action="append", help="Add include path", default=[]
        )
        parser.add_argument(
            "--monolithic",
            action="store_true",
            help="Build monolithic test suite",
            default=False,
        )
        parser.add_argument(
            "--coverage",
            action="store_true",
            help="Build with code coverage",
            default=False,
        )
        parser.add_argument(
            "--subninja",
            action="store",
            help="Build as subproject (exclude rules and pools) with the given subpath",
            default="",
        )
        parser.add_argument(
            "--buildprefs",
            action="store",
            help="Read the given build preferences file",
            default="",
        )
        parser.add_argument(
            "--updatebuild",
            action="store_true",
            help="Update submodule build scripts",
            default="",
        )
        parser.add_argument(
            "--lto",
            action="store_true",
            help="Build with Link Time Optimization",
            default=False,
        )
        options = parser.parse_args()

        self.project = project
        self.target = platform.Platform(options.target)
        self.host = platform.Platform(options.host)
        self.subninja = options.subninja
        archs = options.arch
        configs = options.config
        if includepaths is None:
            includepaths = []
        if not options.includepath is None:
            includepaths += options.includepath

        buildfile = open("build.ninja", "w")
        self.writer = syntax.Writer(buildfile)

        self.writer.variable("ninja_required_version", "1.3")
        self.writer.newline()

        self.writer.comment("configure.py arguments")
        self.writer.variable("configure_args", " ".join(sys.argv[1:]))
        self.writer.newline()

        self.writer.comment("configure options")
        self.writer.variable("configure_target", self.target.platform)
        self.writer.variable("configure_host", self.host.platform)

        env_keys = set(["CC", "AR", "LINK", "CFLAGS", "ARFLAGS", "LINKFLAGS"])
        configure_env = dict(
            (key, os.environ[key]) for key in os.environ if key in env_keys
        )
        if configure_env:
            config_str = " ".join(
                [key + "=" + pipes.quote(configure_env[key]) for key in configure_env]
            )
            self.writer.variable("configure_env", config_str + "$ ")

        if variables is None:
            variables = {}
        if not isinstance(variables, dict):
            variables = dict(variables)

        if options.monolithic:
            variables["monolithic"] = True
        if options.coverage:
            variables["coverage"] = True
        if options.lto:
            variables["lto"] = True
        if self.subninja != "":
            variables["internal_deps"] = True

        self.toolchain = toolchain.make_toolchain(
            self.host, self.target, options.toolchain
        )
        self.toolchain.buildprefs = options.buildprefs
        self.toolchain.initialize(
            project,
            archs,
            configs,
            includepaths,
            dependlibs,
            libpaths,
            variables,
            self.subninja,
        )

        self.writer.variable("configure_toolchain", self.toolchain.name())
        self.writer.variable("configure_archs", archs)
        self.writer.variable("configure_configs", configs)
        self.writer.newline()

        self.toolchain.write_variables(self.writer)
        if self.subninja == "":
            self.toolchain.write_rules(self.writer)

    def target(self):
        return self.target

    def host(self):
        return self.host

    def toolchain(self):
        return self.toolchain

    def writer(self):
        return self.writer

    def is_subninja(self):
        return self.subninja != ""

    def lib(
        self,
        module,
        sources,
        libname=None,
        basepath=None,
        configs=None,
        includepaths=None,
        variables=None,
    ):
        return self.toolchain.lib(
            self.writer,
            module,
            sources,
            libname,
            basepath,
            configs,
            includepaths,
            variables,
        )

    def sharedlib(
        self,
        module,
        sources,
        libname=None,
        basepath=None,
        configs=None,
        includepaths=None,
        libpaths=None,
        implicit_deps=None,
        dependlibs=None,
        libs=None,
        frameworks=None,
        variables=None,
    ):
        return self.toolchain.sharedlib(
            self.writer,
            module,
            sources,
            libname,
            basepath,
            configs,
            includepaths,
            libpaths,
            implicit_deps,
            dependlibs,
            libs,
            frameworks,
            variables,
        )

    def bin(
        self,
        module,
        sources,
        binname,
        basepath=None,
        configs=None,
        includepaths=None,
        libpaths=None,
        implicit_deps=None,
        dependlibs=None,
        libs=None,
        frameworks=None,
        variables=None,
    ):
        return self.toolchain.bin(
            self.writer,
            module,
            sources,
            binname,
            basepath,
            configs,
            includepaths,
            libpaths,
            implicit_deps,
            dependlibs,
            libs,
            frameworks,
            variables,
        )

    def app(
        self,
        module,
        sources,
        binname,
        basepath=None,
        configs=None,
        includepaths=None,
        libpaths=None,
        implicit_deps=None,
        dependlibs=None,
        libs=None,
        frameworks=None,
        variables=None,
        resources=None,
    ):
        return self.toolchain.app(
            self.writer,
            module,
            sources,
            binname,
            basepath,
            configs,
            includepaths,
            libpaths,
            implicit_deps,
            dependlibs,
            libs,
            frameworks,
            variables,
            resources,
        )

    def test_includepaths(self):
        # TODO: This is ugly
        if self.project == "foundation":
            return ["test"]
        foundation_path = os.path.join("..", "foundation_lib")
        if not os.path.isfile(
            os.path.join(foundation_path, "foundation", "foundation.h")
        ):
            foundation_path = os.path.join("..", "foundation")
        return ["test", os.path.join(foundation_path, "test")]

    def test_monolithic(self):
        return self.toolchain.is_monolithic()
